package com.bootdo.system.config;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import cn.hutool.core.codec.Base64;

import com.bootdo.common.config.Constant;
import com.bootdo.common.redis.shiro.RedisCacheManager;
import com.bootdo.common.redis.shiro.RedisManager;
import com.bootdo.common.redis.shiro.RedisSessionDAO;
import com.bootdo.system.shiro.UserRealm;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.SessionListener;
import org.apache.shiro.session.mgt.eis.MemorySessionDAO;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;

/**
 * @author bootdo 1992lcg@163.com
 */
@Configuration
public class ShiroConfig {
    @Value("${spring.redis.host}")
    private String host;
    @Value("${spring.redis.password}")
    private String password;
    @Value("${spring.redis.port}")
    private int port;
    @Value("${spring.redis.timeout}")
    private int timeout;

    @Value("${cacheType}")
    private String cacheType;

    @Value("${server.session-timeout}")
    private int tomcatTimeout;
    

    // 设置Cookie的域名
    @Value("${shiro.cookie.domain}")
    private String domain;

    // 设置cookie的有效访问路径
    @Value("${shiro.cookie.path}")
    private String path;

    // 设置HttpOnly属性
    @Value("${shiro.cookie.httpOnly}")
    private boolean httpOnly;

    // 设置Cookie的过期时间，秒为单位
    @Value("${shiro.cookie.maxAge}")
    private int maxAge;


    @Bean
    public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    /**
     * ShiroDialect，为了在thymeleaf里使用shiro的标签的bean
     * @return
     */
    @Bean
    public ShiroDialect shiroDialect() {
        return new ShiroDialect();
    }

	@Bean
    ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
		shiroFilterFactoryBean.setSecurityManager(securityManager);
		shiroFilterFactoryBean.setLoginUrl("/login");
		shiroFilterFactoryBean.setSuccessUrl("/index");
		shiroFilterFactoryBean.setUnauthorizedUrl("/403");
		LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
		filterChainDefinitionMap.put("/login", "anon");
		filterChainDefinitionMap.put("/alipay/tradePrecreatePay", "anon");
		filterChainDefinitionMap.put("/alipay/return_url", "anon");
		filterChainDefinitionMap.put("/alipay/notify_url", "anon");
		filterChainDefinitionMap.put("/css/**", "anon");
		filterChainDefinitionMap.put("/js/**", "anon");
		filterChainDefinitionMap.put("/fonts/**", "anon");
		filterChainDefinitionMap.put("/img/**", "anon");
		filterChainDefinitionMap.put("/docs/**", "anon");
		filterChainDefinitionMap.put("/druid/**", "anon");
		filterChainDefinitionMap.put("/upload/**", "anon");
		filterChainDefinitionMap.put("/files/**", "anon");
		filterChainDefinitionMap.put("/users/**", "anon");
		filterChainDefinitionMap.put("/logout", "logout");
		filterChainDefinitionMap.put("/sendMsg", "anon");
		filterChainDefinitionMap.put("/sendMsgRes", "anon");
		filterChainDefinitionMap.put("/register", "anon");
		filterChainDefinitionMap.put("/register2", "anon");
		filterChainDefinitionMap.put("/forgetPhone", "anon");
		filterChainDefinitionMap.put("/findPwd", "anon");
		filterChainDefinitionMap.put("/updatePwd", "anon");
		filterChainDefinitionMap.put("/r/**", "anon");
		filterChainDefinitionMap.put("/sys/user/exit", "anon");
		filterChainDefinitionMap.put("/sys/user/payNotes", "anon");
		filterChainDefinitionMap.put("/sys/user/noexit", "anon");
		filterChainDefinitionMap.put("/forget", "anon");
		filterChainDefinitionMap.put("/forgetOne", "anon");
		filterChainDefinitionMap.put("/blog", "anon");
		filterChainDefinitionMap.put("/blog/open/**", "anon");
		filterChainDefinitionMap.put("/wechatpay/topay", "anon");
		//移动端
		filterChainDefinitionMap.put("/blog/bContent/mobileadd", "anon");//我要投诉
		filterChainDefinitionMap.put("/friendcircle/friendCircleMessage/list", "anon");//速用朋友圈
		filterChainDefinitionMap.put("/friendcircle/friendCircleMessage/toPic", "anon");//速用朋友圈
		filterChainDefinitionMap.put("/loa/tbMedia/**", "anon");
		
		filterChainDefinitionMap.put("/system/sowingmap/addjoinpolicylist","anon");//移动端加盟政策
		filterChainDefinitionMap.put("/system/sowingmap/addtrainlist","anon");//移动端公司培训
		filterChainDefinitionMap.put("/system/sowingmap/addemploylist","anon");//移动端公司招聘
		filterChainDefinitionMap.put("/system/sowingmap/addintroducelist","anon");//移动端公司介绍
		filterChainDefinitionMap.put("/system/sowingmap/addpaylist","anon");//移动端移动支付
		filterChainDefinitionMap.put("/system/sowingmap/addchatlist","anon");//移动端社交广告
		filterChainDefinitionMap.put("/system/sowingmap/addworklist","anon");//移动端业务合作
		filterChainDefinitionMap.put("/system/sowingmap/addAdvertisingPicturelist", "anon");//移动端轮播广告
		filterChainDefinitionMap.put("/system/dealSlideshow/list", "anon");//交易中心轮播图
		
		filterChainDefinitionMap.put("/system/sowingmap/homepagelist","anon");//移动端主页展示
		filterChainDefinitionMap.put("/system/sowingmap/lunbolist","anon");//移动端轮播图
		filterChainDefinitionMap.put("/news/openapp/post/**","anon");//新闻详情接口
		filterChainDefinitionMap.put("/news/bContent/list","anon");//新闻遍历接口
		filterChainDefinitionMap.put("/system/wechat/myCollection","anon");//我的收藏
		filterChainDefinitionMap.put("/sys/user/appPersonal","anon");//个人中心
		filterChainDefinitionMap.put("/system/wechat/list","anon");//小程序模板遍历
		filterChainDefinitionMap.put("/system/wechat/applist","anon");//小程序模板详情
		filterChainDefinitionMap.put("/system/wechat/myCollectionList", "anon");//移动端我的收藏遍历
		filterChainDefinitionMap.put("/mobileshare","anon");//小程序移动端分享
		filterChainDefinitionMap.put("/system/sowingmap/list", "anon");
		filterChainDefinitionMap.put("/system/company/getById", "anon");//单个公司详情
		filterChainDefinitionMap.put("/system/company/saveDemo", "anon");//单个公司详情
		filterChainDefinitionMap.put("/system/company/saveInput", "anon");//单个公司详情
		filterChainDefinitionMap.put("/system/company/list", "anon");
		filterChainDefinitionMap.put("/system/advertising/save", "anon");//发布广告
		filterChainDefinitionMap.put("/system/manage/save", "anon");//发布合作运营
		filterChainDefinitionMap.put("/system/merchant/save", "anon");//发布商家
		filterChainDefinitionMap.put("/system/miniappDetails/save", "anon");//发布小程序
		filterChainDefinitionMap.put("/system/operator/save", "anon");//发布运营商
		filterChainDefinitionMap.put("/system/advertising/getListByStatus", "anon");//通过审核的广告
		filterChainDefinitionMap.put("/system/manage/getListByStatus", "anon");//通过审核的合作运营
		filterChainDefinitionMap.put("/system/merchant/getListByStatus", "anon");//通过审核的商家
		filterChainDefinitionMap.put("/system/miniappDetails/getListByStatus", "anon");//通过审核的小程序
		filterChainDefinitionMap.put("/system/operator/getListByStatus", "anon");//通过审核的运营商
		filterChainDefinitionMap.put("/system/advertising/detailsPage", "anon");//移动端广告详情页面
		filterChainDefinitionMap.put("/system/manage/detailsPage", "anon");//移动端合作运营详情页面
		filterChainDefinitionMap.put("/system/miniappDetails/detailsPage", "anon");//移动端小程序详情页面
		filterChainDefinitionMap.put("/system/operator/detailsPage", "anon");//移动端运营商详情页面
		filterChainDefinitionMap.put("/system/merchant/detailsPage", "anon");//移动端商家详情页面
		filterChainDefinitionMap.put("/system/userpic/save", "anon");//移动端编辑头像
		filterChainDefinitionMap.put("/system/userpic/getUserpic", "anon");//移动端查询头像
		filterChainDefinitionMap.put("/friendcircle/friendCircleMessage/list", "anon");//朋友圈
		filterChainDefinitionMap.put("/sys/user/test", "anon");//接口
		filterChainDefinitionMap.put("/wx/share/getSignature", "anon");//微信分享权限数据接口
		filterChainDefinitionMap.put("/loa/tbMedia/adddemo", "anon");//防止表单提交重复接口
		filterChainDefinitionMap.put("/sys/user/mySelfGpsMapdemo", "anon");//地图接口
		filterChainDefinitionMap.put("/MP_verify_KbJazcz6PvWFI7fP.txt","anon");//微信服务号校验
		filterChainDefinitionMap.put("/MP_verify_4J1fSrcH41Otr5qH.txt","anon");//微信服务号校验
		filterChainDefinitionMap.put("/shareRegister","anon");
		filterChainDefinitionMap.put("/loa/tbMedia/mobile","anon");//移动端视频中心遍历接口
		filterChainDefinitionMap.put("/loa/tbMedia/share","anon");//微信分享视频遍历
		filterChainDefinitionMap.put("/loa/tbMedia/saveshare","anon");//微信分享视频新增
		filterChainDefinitionMap.put("/getCode","anon");
		filterChainDefinitionMap.put("/**", "user");
		shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
		return shiroFilterFactoryBean;
	}

    
	/**  
	  * cookie对象;  
	  * rememberMeCookie()方法是设置Cookie的生成模版，比如cookie的name，cookie的有效时间等等。  
	  * @return  
	 */  
	@Bean  
	public SimpleCookie rememberMeCookie(){  
		    SimpleCookie cookie = new SimpleCookie("rememberMe");
	        cookie.setDomain(domain);
	        cookie.setPath(path);
	        cookie.setHttpOnly(httpOnly);
	        cookie.setMaxAge(maxAge * 24 * 60 * 60);
	        return cookie;
	}  
	
	
	/**  
	  * cookie管理对象;  
	  * rememberMeManager()方法是生成rememberMe管理器，而且要将这个rememberMe管理器设置到securityManager中  
	  * @return  
	 */  
	@Bean  
	public CookieRememberMeManager rememberMeManager(){  
		   CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
	        cookieRememberMeManager.setCookie(rememberMeCookie());
	        cookieRememberMeManager.setCipherKey(Base64.decode("fCq+/xW488hMTCD+cmJ3aQ=="));
	        return cookieRememberMeManager;
	}  
	
	
	
    @Bean
    public SecurityManager securityManager(){
        DefaultWebSecurityManager securityManager =  new DefaultWebSecurityManager();
        //设置realm.
        securityManager.setRealm(userRealm());
        //注入记住我管理器  
        securityManager.setRememberMeManager(rememberMeManager()); 
        // 自定义缓存实现 使用redis
        if(Constant.CACHE_TYPE_REDIS.equals(cacheType)){
            securityManager.setCacheManager(cacheManager()); 
        }else {
            securityManager.setCacheManager(ehCacheManager());
        }
        securityManager.setSessionManager(sessionManager());
        return securityManager;
    }

	@Bean
    UserRealm userRealm() {
		UserRealm userRealm = new UserRealm();
		return userRealm;
	}

    /**
     *  开启shiro aop注解支持.
     *  使用代理方式;所以需要开启代码支持;
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    /**
     * 配置shiro redisManager
     * @return
     */
    @Bean
    public RedisManager redisManager() {
        RedisManager redisManager = new RedisManager();
        redisManager.setHost(host);
        redisManager.setPort(port);
        redisManager.setExpire(1800);// 配置缓存过期时间
        //redisManager.setTimeout(1800);
        redisManager.setPassword(password);
        return redisManager;
    }

    /**
     * cacheManager 缓存 redis实现
     * 使用的是shiro-redis开源插件
     * @return
     */
    public RedisCacheManager cacheManager() {
        RedisCacheManager redisCacheManager = new RedisCacheManager();
        redisCacheManager.setRedisManager(redisManager());
        return redisCacheManager;
    }


    /**
     * RedisSessionDAO shiro sessionDao层的实现 通过redis
     * 使用的是shiro-redis开源插件
     */
    @Bean
    public RedisSessionDAO redisSessionDAO() {
        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
        redisSessionDAO.setRedisManager(redisManager());
        return redisSessionDAO;
    }

    @Bean
    public SessionDAO sessionDAO(){
        if(Constant.CACHE_TYPE_REDIS.equals(cacheType)){
            return redisSessionDAO();
        }else {
            return new MemorySessionDAO();
        }
    }

    /**
     * shiro session的管理
     */
    @Bean
    public DefaultWebSessionManager sessionManager() {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setGlobalSessionTimeout(tomcatTimeout*1000);
        sessionManager.setSessionDAO(sessionDAO());
        Collection<SessionListener> listeners = new ArrayList<SessionListener>();
        listeners.add(new BDSessionListener());
        sessionManager.setSessionListeners(listeners);
        return sessionManager;
    }
    @Bean
    public EhCacheManager ehCacheManager() {
        EhCacheManager em = new EhCacheManager();
        em.setCacheManagerConfigFile("classpath:config/ehcache.xml");
        return em;
    }

}
